class WebSocketService {
  constructor() {
    this.ws = null;
    this.reconnectAttempts = 0;
    this.maxReconnectAttempts = 5;
    this.reconnectDelay = 1000; // Start with 1 second
    this.maxReconnectDelay = 30000; // Max 30 seconds
    this.isConnecting = false;
    this.messageHandlers = new Map();
    this.connectionState = 'disconnected'; // 'connecting', 'connected', 'disconnected'
  }

  connect(url = null) {
    if (this.isConnecting || this.ws?.readyState === WebSocket.OPEN) {
      return;
    }

    // Use provided URL or construct from current location
    const wsUrl = url || this.getWebSocketUrl();

    this.isConnecting = true;
    this.connectionState = 'connecting';

    // Add a small delay to ensure Vite proxy is ready
    setTimeout(() => {
      try {
        this.ws = new WebSocket(wsUrl);
        
        this.ws.onopen = () => {
          console.log('[WebSocket] Connected');
          this.connectionState = 'connected';
          this.isConnecting = false;
          this.reconnectAttempts = 0;
          this.reconnectDelay = 1000;
        };

        this.ws.onmessage = (event) => {
          try {
            const message = JSON.parse(event.data);
            this.handleMessage(message);
          } catch (error) {
            console.error('[WebSocket] Error parsing message:', error);
          }
        };

        this.ws.onclose = (event) => {
          console.log('[WebSocket] Disconnected:', event.code, event.reason);
          this.connectionState = 'disconnected';
          this.isConnecting = false;
          
          if (!event.wasClean && this.reconnectAttempts < this.maxReconnectAttempts) {
            this.scheduleReconnect();
          }
        };

        this.ws.onerror = (error) => {
          console.error('[WebSocket] Error:', error);
          this.connectionState = 'disconnected';
          this.isConnecting = false;
        };

      } catch (error) {
        console.error('[WebSocket] Connection error:', error);
        this.connectionState = 'disconnected';
        this.isConnecting = false;
        this.scheduleReconnect();
      }
    }, 1000); // 1 second delay
  }

  getWebSocketUrl() {
    // In development, use the proxy
    if (import.meta.env.DEV) {
      const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
      return `${protocol}//${window.location.host}/ws`;
    }
    
    // In production, use the API base URL
    // You can customize this by setting VITE_API_BASE_URL in your .env file
    // Example: VITE_API_BASE_URL=http://your-backend-server:8080
    const apiBaseUrl = import.meta.env.VITE_API_BASE_URL || 'http://localhost:9095';
    const wsUrl = apiBaseUrl.replace(/^http/, 'ws');
    return `${wsUrl}/ws`;
  }

  scheduleReconnect() {
    if (this.reconnectAttempts >= this.maxReconnectAttempts) {
      console.log('[WebSocket] Max reconnection attempts reached');
      return;
    }

    this.reconnectAttempts++;
    const delay = Math.min(this.reconnectDelay * Math.pow(2, this.reconnectAttempts - 1), this.maxReconnectDelay);
    
    console.log(`[WebSocket] Reconnecting in ${delay}ms (attempt ${this.reconnectAttempts}/${this.maxReconnectAttempts})`);
    
    setTimeout(() => {
      this.connect();
    }, delay);
  }

  disconnect() {
    if (this.ws) {
      this.ws.close(1000, 'Client disconnect');
      this.ws = null;
    }
    this.connectionState = 'disconnected';
    this.isConnecting = false;
  }

  send(message) {
    if (this.ws && this.ws.readyState === WebSocket.OPEN) {
      this.ws.send(JSON.stringify(message));
    } else {
      console.warn('[WebSocket] Cannot send message - not connected');
    }
  }

  sendPing() {
    this.send({
      type: 'ping',
      timestamp: new Date().toISOString()
    });
  }

  handleMessage(message) {
    // console.log('[WebSocket] Received message:', message.type);
    
    const handlers = this.messageHandlers.get(message.type);
    if (handlers) {
      handlers.forEach(handler => {
        try {
          handler(message.payload, message.timestamp);
        } catch (error) {
          console.error('[WebSocket] Error in message handler:', error);
        }
      });
    }
  }

  onMessage(type, handler) {
    if (!this.messageHandlers.has(type)) {
      this.messageHandlers.set(type, []);
    }
    this.messageHandlers.get(type).push(handler);
  }

  offMessage(type, handler) {
    const handlers = this.messageHandlers.get(type);
    if (handlers) {
      const index = handlers.indexOf(handler);
      if (index > -1) {
        handlers.splice(index, 1);
      }
    }
  }

  getConnectionState() {
    return this.connectionState;
  }

  isConnected() {
    return this.ws?.readyState === WebSocket.OPEN;
  }
}

// Create a singleton instance
const websocketService = new WebSocketService();

export default websocketService; 